package cn.ilikes.tools.nosql.jpa.metadatas.processor;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;

import cn.ilikes.tools.logs.Loggerfactory;
import cn.ilikes.tools.nosql.jpa.annotations.IndexColumn;
import cn.ilikes.tools.nosql.jpa.annotations.IndexColumn.Index;
import cn.ilikes.tools.nosql.jpa.metadatas.EntityMetaData;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.EntityFields;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.IndexField;
import cn.ilikes.tools.nosql.jpa.metadatas.elements.Relation;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.ElementProcessorException;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.EntityFieldElementProcessors;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.EntityTableProcessors;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.ManyToOneRelationProcessor;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.OneToManyRelationProcessor;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.OneToOneRelationProcessor;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.processores.Processors;
import cn.ilikes.tools.nosql.jpa.metadatas.processor.validators.EntityValidatorException;

public class TableProcessor extends AbstractEntityProcessor {

	public static void processorsIndexColumn(EntityFields entityFields, Field f) {
		IndexColumn indexColumn = f.getAnnotation(IndexColumn.class);
		if (indexColumn == null) {
			IndexField indexField = new IndexField(false);
			entityFields.setIndexField(indexField);
		} else {
			IndexField indexField = new IndexField(true);
			indexField.setName((indexColumn.name().isEmpty() ? f.getName() : indexColumn.name()));
			indexField.setIndex(indexColumn.index());
			indexField.setBoost(indexColumn.boost());
			indexField.setStore(indexColumn.store());
			indexField.setTermVector(indexColumn.termvector());
			entityFields.setIndexField(indexField);
		}

	}

	public static void processorsRelationIndexColumn(EntityFields entityFields, Field f, Relation relation) {
		IndexColumn indexColumn = f.getAnnotation(IndexColumn.class);
		if (indexColumn != null) {
			IndexField indexField = new IndexField(true);
			indexField.setName((indexColumn.name().isEmpty() ? relation.getJoinColumnName() : indexColumn.name()));
			indexField.setIndex(indexColumn.index());
			indexField.setBoost(indexColumn.boost());
			indexField.setStore(indexColumn.store());
			indexField.setTermVector(indexColumn.termvector());
			entityFields.setIndexField(indexField);
		} else {
			IndexField indexField = new IndexField(true);
			indexField.setName(relation.getJoinColumnName());
			indexField.setIndex(Index.not_analyzed);
			indexField.setBoost(1.0f);
			indexField.setStore(IndexColumn.Store.no);
			indexField.setTermVector(IndexColumn.TermVector.no);
			entityFields.setIndexField(indexField);
		}

	}

	private Logger logger = Loggerfactory.instance(TableProcessor.class);

	private List<Processors> entityProcessors = new ArrayList<Processors>();

	public TableProcessor() {

		entityProcessors.add(new EntityTableProcessors());
		entityProcessors.add(new EntityFieldElementProcessors());
		entityProcessors.add(new OneToOneRelationProcessor());
		entityProcessors.add(new OneToManyRelationProcessor());
		entityProcessors.add(new ManyToOneRelationProcessor());
	}

	@Override
	public void process(Class<?> clazz, EntityMetaData metadata) throws TableProcessorException {
		Loggerfactory.info(logger, "start  processor table entity [ " + clazz.getSimpleName() + " ] ");
		if (!entityValidator(clazz, metadata))

		{
			throw new TableProcessorException("table entity [ " + clazz.getSimpleName() + " ] entity validator no  success ! ");
		}
		for (Processors processors : entityProcessors) {
			try {
				processors.processors(clazz, metadata);
			} catch (ElementProcessorException e) {
				Loggerfactory.error(logger, e);
				throw new TableProcessorException(e);
			}

		}
	}

	@Override
	protected boolean entityValidator(Class<?> clazz, EntityMetaData metadata) {

		for (Processors processors : entityProcessors) {
			try {
				processors.validators(clazz, metadata);
			} catch (EntityValidatorException e) {
				Loggerfactory.error(logger, e);
				return false;
			}
		}
		return true;
	}

}
